<?php
/*
 * Created on 2008. 8. 18.
 *
 * creator : cho sung hoon (akdddnet@gmail.com)
 * 
 * comment : 
 *     - event를 array로 넘기는데 이걸 객체로 정의해서 전달하는게 좋을듯. (객체나 배열이나 별차이가 없기 때문에.. 일단은 패스... 08. 18);;
 *     - autoload로 자동으로 include하게 할수 있는데 이건 부하를 증가 시키기 때문에 되도록 사용하지 않는게 좋을듯..
 * 
 * ex) 기본사용법 
 * 		$logger = new Logger();
 *		$logger->Write("가나다라마바사", Logger::INFO);
 *     ---------------------------------------------
 * 	       확장 사용법 (상황에 따라 format형식을 변경할수 있음., filter기능도 추가해야되는데... 아무래도. 출력형태도(stream, db 등등) 따로 만들어야될듯 ㅠ)
 *      $format = new HtmlFormat();
 *		$logger->SetFormat($format);
 *		$logger->Write('가나다라마바사', Logger::INFO);
 *
 * 수정사항
 * 2008. 09. 09 by akddd
 *   - Logleve추가
 * 
 * 2008. 09. 16?? by akddd 
 *   - 싱글톤 패턴으로 변환 
 * 
 * 2010. 12. 30
 * 	 - IMessenger 걷어냄.
 *   - 함수명 변경으로 인해 소스 코드 전체적으로 수정. 
 */
 
 	require_once 'config.php';
	global $CFG;
	
 	require_once $CFG->FW_DIR.'/log/LogAbstract.php';
 	require_once $CFG->FW_DIR.'/log/format/SimpleFormat.php';
 	
 	require_once $CFG->FW_DIR.'/file/Directorys.php';
 	require_once $CFG->FW_DIR.'/file/Files.php';
 	
 	require_once $CFG->FW_DIR.'/utility/Common.php';
 
 	/**
 	 * Log 기록을 남깁니다.
 	 */
	class Logger extends LogAbstract
	{
		// 로그 레벨 정리
		// ZendFramework와 동일함. (숫자가 낮을수록 치명적)
		const EMERG   = 0;  // Emergency: system is unusable
	    const ALERT   = 1;  // Alert: action must be taken immediately
	    const CRIT    = 2;  // Critical: critical conditions
	    const ERR     = 3;  // Error: error conditions
	    const WARN    = 4;  // Warning: warning conditions
	    const NOTICE  = 5;  // Notice: normal but significant condition
	    const INFO    = 6;  // Informational: informational messages
	    const DEBUG   = 7;  // Debug: debug messages
	    
	    
	    protected $_priorities = array();
	    //protected $_writers = array(); //한개의 로그 정보를 여러 파일이나, DB에 저장할 경우는 거의 없기에.. 필요할때 만들어야될듯.
	    
	    protected $_default_path;
	    protected $_file_path;
	    protected $_file_name;
	    
	    //private $_cfg;
	    private static $logger;			// 싱글톤 패턴
	    
	    //private $_stream = array(); 	// file open 
	    
		function __construct($file_name=null, $file_path=null)
		{
			global $CFG;
			//$this->_cfg = $CFG;
			$this->_default_path = $CFG->LOG_DIR;
			
			// ReflectionClass : http://kr2.php.net/manual/en/language.oop5.reflection.php
			// ZendFramework Logger참고함.
			$r = new ReflectionClass($this);
			$this->_priorities = array_flip($r->getConstants());
			
			if(is_null($file_path))
			{
				$this->file_path = date('Y/m/'); 
				$this->makeDirectory($this->file_path, true);
			}
			else 
			{
				$this->file_path = $file_path; 
				$this->makeDirectory($this->file_path, false);
			}
				
				
			if(is_null($file_name))
				$this->_file_name = date('Y-m-d');
			else 
				$this->_file_name = $file_name;
				
			// 기본적으로 심플 포멧을 셋팅
			$this->_format = new SimpleFormat();
			$this->AddFilter(new Priority($CFG->LOG_LEVEL));
		
		}
		
		
		/**
		 * 생성된 인스턴스를 반환합니다.
		 * 
		 * @return Logger
		 */
		public static function getInstance()
		{
			if(Common::isNullOrEmpty(Logger::$logger))
				Logger::$logger = new Logger();
				
			return Logger::$logger;
		}
		
		
		/**
		 * Log를 남기기 위해서 호출되는 메소드 입니다.
		 * LogLevel을 입력하지 않으면 EMERG로 출력됩니다.
		 * 
		 * @param string $msg	: 로그 메세지
		 * @param int $priority	: log level
		 */
		public function write($msg, $priority=7)
		{
			if(is_int($priority))
			{
				// '%timestamp% %priorityName% (%priority%): %message%';
				$event = array(	'time'			=>	date('Y-m-d H:i:s'),
								'priorityName'	=>	$this->_priorities[$priority],
								'priority'		=>	$priority,
								'message'		=>	$msg
							);
					
				$this->filter($event);	// LogAbstract에 정의되어 있음. _Write로 이동함.
			}
			else 
				throw new Exception('로그 레벨은 숫자로 입력해야됩니다.');
		}
		
		
		/**
		 * 실제적으로 파일에 로그정보를 남기는 부분입니다. (외부 호출 불가)
		 * 
		 * @param array $event
		 * @return void
		 */
		protected function _write($event)
		{
			if(is_array($event))
			{
				$files = new Files($this->_file_path);
				
				$msg = $this->_format->format($event);
				$files->writeFile($this->_file_name.'.log', $msg);
				
				
				// 예외설정 (시스템 결함적인 메세지는 Error로그 따로 남기기)
				// Error : 3보다 작은건 Error로 따로 분리
				if($event['priority'] <= 3)
				{
					$files->writeFile($this->_file_name.'-Error.log', $msg);
				}
			}
			else 
			{
				throw new Exception('파라메터 형식이 잘못되어 있습니다.');	
			}
		}
		
		/**
		 * log file이 저장될 폴더를 생성 합니다. 
		 * 
		 * @param string directory : 저장될 폴더
		 * @param boolean $default : 기본값인 log폴더에 저장, 다른폴더에 저장할경우 false로 전달해야됩니다.
		 * @return void; 
		 */
		protected function makeDirectory($directory, $default=true)
		{
			if(!is_null($directory))
			{	
				// 기준이 되는 폴더로 directory class선언
				$dirClass = new Directorys($default);
				
				// 저장되는 폴더가 존재하는지 확인 및 폴더 생성
				$dir = explode('/', $directory);
				$tempDirectory = $this->_default_path;
				
				
				foreach($dir as $tmpDir)
				{
					// 빈값이 아닐 경우에만 폴더 생성
					if(!is_null($tmpDir) && !Common::isNullOrEmpty($tmpDir))
					{
						$tempDirectory .= '/'.$tmpDir;
						if(!$dirClass->isDirectory($tempDirectory))
						{
							$dirClass->makeDir($tempDirectory);
						}
					}
				}	
				
				$this->_file_path = $tempDirectory;
			}
			else 
				throw new Exception('폴더명이 입력되지 않았습니다.');
			
		}
	}
	